package com.zzyl.nursing.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.*;
import com.zzyl.common.constant.Constants;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.common.utils.UserThreadLocal;
import com.zzyl.framework.web.service.TokenService;
import com.zzyl.nursing.domain.*;
import com.zzyl.nursing.dto.FamilyMemberDto;
import com.zzyl.nursing.dto.QueryByDayDto;
import com.zzyl.nursing.dto.QueryDevicePropertyStatusDto;
import com.zzyl.nursing.dto.UserLoginRequestDto;
import com.zzyl.nursing.mapper.FamilyMemberElderMapper;
import com.zzyl.nursing.mapper.FamilyMemberMapper;
import com.zzyl.nursing.service.*;
import com.zzyl.nursing.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 老人家属Service业务层处理
 * 
 * @author ruoyi
 */
@Service
public class FamilyMemberServiceImpl extends ServiceImpl<FamilyMemberMapper, FamilyMember> implements IFamilyMemberService
{
    @Autowired
    private FamilyMemberMapper familyMemberMapper;

    @Autowired
    private IDeviceDataService deviceDataService;

    /**
     * 查询老人家属
     * 
     * @param id 老人家属主键
     * @return 老人家属
     */
    @Override
    public FamilyMember selectFamilyMemberById(Long id)
    {
        return getById(id);
    }

    /**
     * 查询老人家属列表
     *
     * @param familyMember 老人家属
     * @return 老人家属
     */
    @Override
    public List<FamilyMember> selectFamilyMemberList(FamilyMember familyMember)
    {
        return familyMemberMapper.selectFamilyMemberList(familyMember);
    }

    /**
     * 新增老人家属
     * 
     * @param familyMember 老人家属
     * @return 结果
     */
    @Override
    public int insertFamilyMember(FamilyMember familyMember)
    {
        return save(familyMember) ? 1 : 0;
    }

    /**
     * 修改老人家属
     * 
     * @param familyMember 老人家属
     * @return 结果
     */
    @Override
    public int updateFamilyMember(FamilyMember familyMember)
    {
        return updateById(familyMember) ? 1 : 0;
    }

    /**
     * 批量删除老人家属
     * 
     * @param ids 需要删除的老人家属主键
     * @return 结果
     */
    @Override
    public int deleteFamilyMemberByIds(Long[] ids)
    {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除老人家属信息
     * 
     * @param id 老人家属主键
     * @return 结果
     */
    @Override
    public int deleteFamilyMemberById(Long id)
    {
        return removeById(id) ? 1 : 0;
    }


    @Autowired
    private WechatService wechatService;

    @Autowired
    private TokenService tokenService;

    static List<String> DEFAULT_NICKNAME_PREFIX = ListUtil.of("生活更美好",
            "大桔大利",
            "日富一日",
            "好柿开花",
            "柿柿如意",
            "一椰暴富",
            "大柚所为",
            "杨梅吐气",
            "天生荔枝"
    );
    @Override
    public LoginVo login(UserLoginRequestDto dto) {
        //1.根据code调用微信api获取apenId
        String openid = wechatService.getOpenid(dto.getCode());
        //2.根据openId查询数据库获取用户信息family_member表
        FamilyMember familyMember = getOne(Wrappers.<FamilyMember>lambdaQuery().eq(FamilyMember::getOpenId, openid));
        //3.判断用户信息是否存在，如果用户为空，则将openId设置到对象中
        if (ObjectUtil.isEmpty(familyMember)){
            familyMember = FamilyMember.builder().openId(openid).build();
        }
        //4.调用微信api获取用户绑定手机号
        String phone = wechatService.getPhone(dto.getPhoneCode());
        // 5.保存或修改用户
        saveOrUpdateFamilyMember(familyMember, phone);
        //6.将用户id存入token中，并返回数据给前端
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", familyMember.getId());
        claims.put("nickName", familyMember.getName());

        String token = tokenService.createToken(claims);
        LoginVo loginVo = new LoginVo();
        loginVo.setToken(token);
        loginVo.setNickName(familyMember.getName());
        return loginVo;
    }

    /**
     * 保存或修改客户
     * @param familyMember
     * @param phone
     */
    private void saveOrUpdateFamilyMember(FamilyMember familyMember, String phone) {
        // 1.判断取到的手机号与数据库中保存的手机号不一样
        if (!phone.equals(familyMember.getPhone())){
            familyMember.setPhone(phone);
        }
        // 2.判断id存在，则修改
        if (familyMember.getId()!= null){
            updateById(familyMember);
            return;
        }
        // 3.id不存在，保存新用户
        // 随机组装昵称，词组+手机号后四位
        String nickName = DEFAULT_NICKNAME_PREFIX.get((int) (Math.random() * DEFAULT_NICKNAME_PREFIX.size()))
                + StringUtils.substring(familyMember.getPhone(), 7);
        familyMember.setName(nickName);
        save(familyMember);
    }


    /**
     * 绑定家人
     */
    @Autowired
    private IElderService elderService;

    @Autowired
    private IFamilyMemberElderService familyMemberElderService;

    @Override
    public void addFamilyMember(FamilyMemberDto dto) {
        // 根据身份证查询老人
        Elder elder = elderService.lambdaQuery()
                .eq(Elder::getIdCardNo, dto.getIdCard())
                .one();

        // 加上 null 判断
        if (elder == null) {
            throw new BaseException("未找到对应老人，请确认身份证号码是否正确");
        }

        // 此时 elder 非 null，可以安全调用 getStatus()
        if (elder.getStatus() == 0 || elder.getStatus() == 5) {
            throw new BaseException("该老人已不在院内");
        }

        if (!dto.getName().equals(elder.getName())) {
            throw new BaseException("姓名不一致");
        }

        //获取当前登录家属id
        Long userId = UserThreadLocal.getUserId();
        if (ObjectUtil.isEmpty(userId)) {
            throw new BaseException("请先登录");
        }

        //防止重复绑定：检查该家属是否已绑定此老人
        boolean exists = familyMemberElderService.lambdaQuery()
                .eq(FamilyMemberElder::getFamilyMemberId, userId)
                .eq(FamilyMemberElder::getElderId, elder.getId())
                .exists();

        if (exists) {
            throw new BaseException("您已绑定该老人，无需重复绑定");
        }

        //保存家属-老人关联
        FamilyMemberElder familyMemberElder = new FamilyMemberElder();
        familyMemberElder.setFamilyMemberId(userId);
        familyMemberElder.setElderId(elder.getId());
        familyMemberElder.setRemark(dto.getRemark());

        familyMemberElderService.save(familyMemberElder);
    }

    /**
     * 查询已绑定的老人
     * @return
     */
    @Override
    public List<FamilyMemberVo> queryFamilyMemberList() {
        Long userId = UserThreadLocal.getUserId();
        if (ObjectUtil.isEmpty(userId)){
            return new ArrayList<>();
        }
        List<FamilyMemberVo> familyMemberVos = familyMemberMapper.queryFamilyMemberList(userId);
        return familyMemberVos;
    }

    /**
     * 分页查询已绑定的老人
     * @return
     */
    @Override
    public List<FamilyMemberElderVo> listByPage() {
        List<FamilyMemberElderVo> vos = familyMemberMapper.listByPage();
        return vos;
    }


    /**
     * 查看健康数据
     * @param dto
     * @return
     */
    @Autowired
    private IoTDAClient client;

    @Autowired
    private IDeviceService deviceService;

    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public Map<String, Object> viewHealthData(QueryDevicePropertyStatusDto dto) {

        //1. 查询产品信息
        ShowProductRequest request = new ShowProductRequest();
        request.setProductId(dto.getProductKey());
        ShowProductResponse response;
        //2. 获取服务id
        Map<String, Object> vo = new HashMap<>();
        ShowDeviceShadowResponse response1;
        try {
            //调用华为云接口查询产品信息
            response = client.showProduct(request);
            //查询数据库中设备数据 设备名字不能重复 用设备名字获取设备的iotId
            Device device = deviceService.lambdaQuery().eq(Device::getDeviceName, dto.getDeviceName()).one();
            String iotId = device.getIotId();

            ShowDeviceShadowRequest request1 = new ShowDeviceShadowRequest();
            request1.setDeviceId(iotId);
            response1 = client.showDeviceShadow(request1);
            //获取服务id
            String serviceId = response1.getShadow().get(0).getServiceId();
            //获取服务属性
            List<ServiceCapability> serviceCapabilities = response.getServiceCapabilities();
            List<Map<String, Object>> propertyStatusInfoVo = queryInfo(serviceCapabilities, serviceId, iotId);
            Map<String, Object> map = new HashMap<>();
            //构造返回数据
            map.put("propertyStatusInfo", propertyStatusInfoVo);
            //构建返回数据
            vo.put("list", map);
        } catch (Exception e) {
            throw new BaseException("查询产品详情失败");
        }
        return vo;
    }


    private List<Map<String, Object>> queryInfo(List<ServiceCapability> serviceCapabilities, String serviceId, String iotId) {
        //属性列表集合
        List<Map<String, Object>> list = new ArrayList<>();
        //通过serviceId过滤出需要的属性
        List<ServiceProperty> properties = serviceCapabilities.stream().filter(serviceCapability -> serviceCapability.getServiceId().equals(serviceId)).findFirst().get().getProperties();
        properties.forEach(p -> {
            //解析获得的属性信息
            Map<String, Object> map = new HashMap<>();
            JSONObject jsonObject = JSONUtil.parseObj(p);
            //将属性添加到map里面
            map.put("identifier", jsonObject.get("propertyName"));
            map.put("dataType", jsonObject.get("dataType"));
            map.put("unit", jsonObject.get("unit"));
            map.put("name", jsonObject.get("description"));
            //添加到集合里面
            list.add(map);
        });
        //从redis中获取设备数据
        Object json = redisTemplate.opsForHash().get(Constants.IOT_DEVICE_LAST_DATA, iotId);
        //转成集合,因为存到Redis里面的时候也是集合的形式
        JSONArray jsonArray = JSONUtil.parseArray(json);
        List<DeviceData> deviceData = JSONUtil.toList(jsonArray, DeviceData.class);
        //将这个集合转换成map 其中FunctionId是他的键 value是DeviceData
        Map<String, DeviceData> map = deviceData.stream().collect(Collectors.toMap(DeviceData::getFunctionId, d -> d));
        //将剩余的属性值添加到map里面
        for (Map<String, Object> map1 : list) {
            DeviceData data = map.get(map1.get("identifier"));
            map1.put("value", data.getDataValue());
            LocalDateTime alarmTime = data.getAlarmTime();
            // 定义格式化器（支持你提供的格式）
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmssX");
            // 定义东八区时区
            ZoneId zoneId = ZoneId.of("Asia/Shanghai");
            // 将 LocalDateTime 转换为 ZonedDateTime
            ZonedDateTime zonedDateTime = alarmTime.atZone(zoneId);
            // 获取时间戳（毫秒）
            long time = zonedDateTime.toInstant().toEpochMilli();
            map1.put("time", time);
        }
        return list;
    }


    /**
     * 解绑
     */
    @Autowired
    private FamilyMemberElderMapper familyMemberElderMapper;

    @Override
    public void deleteById(Long id) {
        //删除数据库中的数据
        familyMemberElderMapper.deleteById(id);
    }


    /**
     * 按天统计查询指标数据
     * @param queryByDayDto
     * @return
     */
    @Override
    public ByDayVo queryByDay(QueryByDayDto queryByDayDto) {
        LocalDateTime startTime = LocalDateTimeUtil.of(queryByDayDto.getStartTime());
        LocalDateTime endTime = LocalDateTimeUtil.of(queryByDayDto.getEndTime());
        // 创建结果列表
        List<TongJiVo> result = new ArrayList<>();
        // 从开始日期的00:00开始，每1小时一个时间点
        LocalDateTime currentDate = startTime.toLocalDate().atStartOfDay(); // 获取开始日期的00:00
        LocalDateTime dayEndTime = endTime.toLocalDate().atStartOfDay().plusDays(1); // 结束日期的00:00（下一天）

        while (currentDate.isBefore(dayEndTime)) {
            // 查询当前1小时时间段内的数据
            LocalDateTime periodEnd = currentDate.plusHours(1);
            List<DeviceData> list = deviceDataService.list(Wrappers.<DeviceData>lambdaQuery()
                    .eq(DeviceData::getIotId, queryByDayDto.getIotId())
                    .eq(DeviceData::getFunctionId, queryByDayDto.getFunctionId())
                    .between(DeviceData::getAlarmTime, currentDate, periodEnd)
            );
            // 格式化当前时间点为HH:mm格式（整点）
            String timeStr = currentDate.format(DateTimeFormatter.ofPattern("HH:mm"));
            if (CollUtil.isNotEmpty(list)) {
                // 如果有数据，使用第一条数据的值
                DeviceData data = list.get(0);
                result.add(new TongJiVo(timeStr, Double.valueOf(data.getDataValue())));
            } else {
                // 如果没有数据，使用默认值0
                result.add(new TongJiVo(timeStr, 0.0));
            }
            // 移动到下一个1小时时间段
            currentDate = periodEnd;
        }
        ByDayVo byDayVo = new ByDayVo();
        byDayVo.setData(result);
        byDayVo.setOperationTime(null);
        byDayVo.setCode(200);
        byDayVo.setMsg("查询成功");
        return byDayVo;
    }

    /**
     * 按周统计查询指标数据
     * @param queryByDayDto
     * @return
     */
    @Override
    public ByDayVo queryByWeek(QueryByDayDto queryByDayDto) {
        LocalDateTime endTime = LocalDateTime.now();
        // 开始时间在七天前（包含今天，共7天数据）
        LocalDateTime startTime = endTime.minusDays(6).toLocalDate().atStartOfDay(); // 修正为7天数据
        List<TongJiVo> result = new ArrayList<>();
        // 从7天前开始，每天一个数据点
        LocalDateTime currentDate = startTime;
        LocalDateTime today = endTime.toLocalDate().atStartOfDay(); // 今天的开始时间
        while (!currentDate.isAfter(today)) {
            // 查询当前日期全天的数据
            LocalDateTime dayEnd = currentDate.plusDays(1);
            List<DeviceData> list = deviceDataService.list(Wrappers.<DeviceData>lambdaQuery()
                    .eq(DeviceData::getIotId, queryByDayDto.getIotId())
                    .eq(DeviceData::getFunctionId, queryByDayDto.getFunctionId())
                    .between(DeviceData::getAlarmTime, currentDate, dayEnd)
            );
            // 格式化当前日期为MM.dd格式
            String timeStr = currentDate.format(DateTimeFormatter.ofPattern("MM.dd"));
            if (CollUtil.isNotEmpty(list)) {
                // 如果有数据，使用第一条数据的值
                DeviceData data = list.get(0);
                result.add(new TongJiVo(timeStr, Double.valueOf(data.getDataValue())));
            } else {
                // 如果没有数据，使用默认值0
                result.add(new TongJiVo(timeStr, 0.0));
            }
            // 移动到下一天
            currentDate = currentDate.plusDays(1);
        }
        ByDayVo byDayVo = new ByDayVo();
        byDayVo.setData(result);
        byDayVo.setOperationTime(null);
        byDayVo.setCode(200);
        byDayVo.setMsg("查询成功");
        return byDayVo;
    }

}












